﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using ZedGraph;

namespace NumericalMethod
{
   public partial class CurveFitting : ContentPane
   {
      private StatusForm mStatus;
      private VParser FormulaParser = new VParser();//= new Parser();
      private graphFX graph;
      private int ActiveMethod;
      private PointPairList pArray;
      const string separator = "==================================";

      public CurveFitting()
      {
         InitializeComponent();
         pArray = new PointPairList();
         this.Notes = NoteType.CurveFitting;
      }

      private void methodComboBox_SelectedIndexChanged(object sender, EventArgs e)
      {
         ActiveMethod = methodComboBox.SelectedIndex;
         enableDisable();
      }
      public override void OnLoad()
      {
         mStatus = new StatusForm();
         Parent.Controls.Add(mStatus);
         graph = new graphFX();
         Parent.Controls.Add(graph);
         methodComboBox.SelectedIndex = 0;
         mStatus.HidePanel(2);
      }
      private void enableDisable()
      {
         //xText.Enabled = (ActiveMethod == 0);
         //yText.Enabled = xText.Enabled;
         //label1.Enabled = xText.Enabled;
         //label2.Enabled = xText.Enabled;
         //label3.Enabled = !xText.Enabled;
         //equationText.Enabled = !xText.Enabled;
      }
      private bool parseText()
      {
         string[] str1 = xText.Text.Split(',');
         string[] str2 = yText.Text.Split(',');
         pArray.Clear();

         if (str1.Length != str2.Length)
         {
            MessageBox.Show("x and y count mismatch. If x has 3, then y shoud have 3 also.");
            return false;
         }

         for (int x = 0; x < str1.Length; x++)
         {
            try
            {
               pArray.Add(double.Parse(str1[x].Trim()), double.Parse(str2[x].Trim()));
            }
            catch (Exception)
            {
               MessageBox.Show("Invalid character within parameter");
               return false;
            }
         }
         return true;
      }
      private void button1_Click(object sender, EventArgs e)
      {
         graph.PointsList.Clear();
         //graph.BackPointsList.Clear();
         graph.PlotTitle = methodComboBox.Text;
         if ( parseText() )
         {
            graph.BackPointsList = pArray;
            graph.AddScatterPlot();
            if (ActiveMethod == 0)
            {
               mStatus.AppendOutput("Linear regression.");
               LinearRegression();
            }
            else 
            {
               mStatus.AppendOutput("Polynomial regression.");
               PolynomialRegression(); 
            }
            mStatus.AppendOutput(separator + "<br/><br/>");
         }
      }
      private void LinearRegression()
      {
         double xsquaresum=0;
         double xsum = 0;
         double ysum = 0;
         double xysum = 0;
         foreach( PointPair z in pArray)
         {
            xsum += z.X;
            ysum += z.Y;
            xsquaresum += z.X * z.X;
            xysum += z.X * z.Y;
         }
         mStatus.AppendOutput("Sum of X: "+xsum);
         mStatus.AppendOutput("Sum of Y: " + ysum);
         mStatus.AppendOutput("Sum of X^2: " + xsquaresum);
         mStatus.AppendOutput("Sum of X*Y: "+xysum);
         mStatus.AppendOutput("Calculating...");
         double B = (pArray.Count * xysum - xsum * ysum) / (pArray.Count * xsquaresum - (xsum * xsum));
         mStatus.AppendOutput("B = "+B);
         double A = ysum / pArray.Count - B * xsum / pArray.Count;
         mStatus.AppendOutput("A = " + A);
         mStatus.AppendOutput("Therefore, least-square fit is: ");
         mStatus.AppendOutput("y = " + B + " x "+((A>=0)?"+":"") + A);

         PointPairList lineDraw = new PointPairList();
         lineDraw.Add(pArray[0].X, (B*pArray[0].X)-A);
         lineDraw.Add(pArray[pArray.Count - 1].X, (B*pArray[pArray.Count - 1].X)-A);
         graph.PointsList = lineDraw;
         graph.AddLineOnly();
      }
      private void PolynomialRegression()
      {
         float xsquaresum = 0;
         float n = pArray.Count;
         float xsum = 0;
         float ysum = 0;
         float xysum = 0, xsquareysum = 0, x3sum = 0, x4sum = 0;
         foreach (PointPair z in pArray)
         {
            xsum += (float)z.X;
            ysum += (float)z.Y;
            xsquaresum += (float)(z.X * z.X);
            xysum += (float)(z.X * z.Y);
            xsquareysum += (float)(z.X * z.X * z.Y);
            x3sum += (float)(z.X * z.X * z.X);
            x4sum += (float)(z.X * z.X * z.X * z.X);
         }
         float[,] matrix = { {n, xsum, xsquaresum}, 
                            {xsum, xsquaresum, x3sum},
                            {xsquaresum, x3sum, x4sum}};
         DotNetMatrix.GeneralMatrix a = new DotNetMatrix.GeneralMatrix(LinearSystemForm.MultiDimensionToJagged(matrix,3,3));
         DotNetMatrix.LUDecomposition LU = new DotNetMatrix.LUDecomposition(a);
         DotNetMatrix.GeneralMatrix b = new DotNetMatrix.GeneralMatrix(new double [] {ysum, xysum, xsquareysum}, 3);
         double [][] solved = LU.Solve(b).Array;
         mStatus.AppendOutput("Using LU Decomposition, <br/>a = "+solved[0][0] + "<br/>b = " + solved[1][0] + "<br/>c = " + solved[2][0]);
         mStatus.AppendOutput("Therefore, the least-squares quadratic equation: <br/>y = " + ((solved[0][0] >= 0) ? "+" : "") + solved[0][0]
            + " " + ((solved[1][0] >= 0) ? "+" : "") + solved[1][0] + "x"
            + " " + ((solved[2][0] >= 0) ? "+" : "") + solved[2][0] + "x^2");

         //
         // Build graph.
         //
         double increment = (pArray[pArray.Count-1].X-pArray[0].X)/50;
         PointPairList lineDraw = new PointPairList();

         for (double x = pArray[0].X; x <= pArray[pArray.Count - 1].X; x += increment)
         {
            lineDraw.Add(x, solved[0][0] + solved[1][0]*x + solved[2][0]*x*x);
         }
         graph.PointsList = lineDraw;
         graph.AddLineOnly();
      }
   }
}
